package com.tony.easymvc.core;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.tony.easymvc.core.bean.ConfigModel;
import com.tony.easymvc.core.bean.GeneratorManifest;
import com.tony.easymvc.core.bean.ModuleConfig;
import com.tony.easymvc.core.bean.ModuleModel;

/**
 * 父类项目生成器
 * 
 * @author zhangruiyu tonyruiyu@163.com
 * @date 2017年6月16日 下午4:54:13
 * @since V1.0
 * @version V1.0
 */
public class DefaultProjectGenerator {

    private String                  outPutPath;

    private List<GeneratorManifest> manifests        = Lists.newArrayList();

    private ConfigModel             config;

    private ModuleModel             module;

    private ModuleConfig            mconfig;

    public String                   tmplName         = "tmpl/parent/pom.tmpl";

    String                          tempPath         = "parent";

    public static String            resourcesPath    = "/src/main/resources";

    public static final String      SRC_MAIN_JAVA    = "/src/main/java";
    public static final String      WEBAPP_MAIN_JAVA = "/src/main/webapp";
    
    public static final String[]  environments = new String[] {"dev","test","prod"};
    
    public DefaultProjectGenerator(ConfigModel config, ModuleConfig mconfig, ModuleModel module) {
        super();
        this.mconfig = mconfig;
        this.config = config;
        this.module = module;

        if (mconfig == null) {
            outPutPath = config.getParentProjectPath();
            tempPath = "parent";
        } else {
            outPutPath = config.getParentProjectPath() + "/" + module.getArtifactId();
            tempPath = mconfig.name().toLowerCase();
        }
        tmplName = "tmpl/" + tempPath + "/pom.tmpl";

        loadManifest();
    }

    private void loadManifest() {
        GeneratorManifest manifest = new GeneratorManifest();
        manifest.setFilename("pom.xml");
        manifest.setPath(outPutPath);
        manifest.setTmplName(tmplName);
        manifests.add(manifest);

        if (mconfig == null) {
        	manifest = new GeneratorManifest();
    	    manifest.setFilename("README.MD");
    	    manifest.setPath(outPutPath);
    	    manifest.setTmplName("tmpl/parent/README.tmpl");
    	    manifests.add(manifest);
        	return;
        }
            

        if (ModuleConfig.BIZ_COMMON.equals(mconfig)) {
            String _srcPath = outPutPath + SRC_MAIN_JAVA + "/" + config.getAnnotationPackage().replaceAll("\\.", "/") + "/biz/common/service";

            manifest = new GeneratorManifest();
            manifest.setFilename("BaseService.java");
            manifest.setPath(_srcPath);
            manifest.setTmplName("tmpl/" + tempPath + "/BaseService.tmpl");
            manifests.add(manifest);
            
            
            _srcPath = outPutPath + SRC_MAIN_JAVA + "/" + config.getAnnotationPackage().replaceAll("\\.", "/") + "/biz/common/utils";
            manifest = new GeneratorManifest();
            manifest.setFilename("ReflectionUtils.java");
            manifest.setPath(_srcPath);
            manifest.setTmplName("tmpl/" + tempPath + "/ReflectionUtils.tmpl");
            manifests.add(manifest);
            
            manifest = new GeneratorManifest();
            manifest.setFilename("ExportExcelUtils.java");
            manifest.setPath(_srcPath);
            manifest.setTmplName("tmpl/" + tempPath + "/ExportExcelUtils.tmpl");
            manifests.add(manifest);
            
            manifest = new GeneratorManifest();
            manifest.setFilename("MappingLoaderUtils.java");
            manifest.setPath(_srcPath);
            manifest.setTmplName("tmpl/" + tempPath + "/MappingLoaderUtils.tmpl");
            manifests.add(manifest);
            
            manifest = new GeneratorManifest();
            manifest.setFilename("ValidatorUtils.java");
            manifest.setPath(_srcPath);
            manifest.setTmplName("tmpl/" + tempPath + "/ValidatorUtils.tmpl");
            manifests.add(manifest);
            
            _srcPath = outPutPath + SRC_MAIN_JAVA + "/" + config.getAnnotationPackage().replaceAll("\\.", "/") + "/biz/common/utils/redis";
            manifest = new GeneratorManifest();
            manifest.setFilename("ConsistentHash.java");
            manifest.setPath(_srcPath);
            manifest.setTmplName("tmpl/" + tempPath + "/ConsistentHash.tmpl");
            manifests.add(manifest);
            
            manifest = new GeneratorManifest();
            manifest.setFilename("RedisClient.java");
            manifest.setPath(_srcPath);
            manifest.setTmplName("tmpl/" + tempPath + "/RedisClient.tmpl");
            manifests.add(manifest);
            
            manifest = new GeneratorManifest();
            manifest.setFilename("RedisUtil.java");
            manifest.setPath(_srcPath);
            manifest.setTmplName("tmpl/" + tempPath + "/RedisUtil.tmpl");
            manifests.add(manifest);

        }

        
        if (ModuleConfig.DAL.equals(mconfig)) {
            // dal
            manifest = new GeneratorManifest();
            manifest.setFilename("spring-dal-auto-" + module.getBizName() + ".xml");
            manifest.setPath(outPutPath + resourcesPath + "/spring");
            manifest.setTmplName("tmpl/" + tempPath + "/spring-dal-auto-core.tmpl");
            manifests.add(manifest);
        }

        if (ModuleConfig.DATASOURCE.equals(mconfig)) {
            manifest = new GeneratorManifest();
            manifest.setFilename("spring-datasource-core.xml");
            manifest.setPath(outPutPath + resourcesPath + "/spring");
            manifest.setTmplName("tmpl/" + tempPath + "/spring-datasource-core.tmpl");
            manifests.add(manifest);

            createJavaModel("ReadOnly");
            createJavaModel("Writer");
            createJavaModel("CustomerContextHolder");
            createJavaModel("DataSourceMap");
            createJavaModel("DynamicDataSource");
            createJavaModel("ClassPathMapperScanner");
            createJavaModel("MapperFactoryBeanInvocation");
            createJavaModel("MapperScannerConfigurer");
            createJavaModel("MyBatisUtil");
        }
        if(ModuleConfig.API.equals(mconfig)) {
            String _srcPath = outPutPath + SRC_MAIN_JAVA + "/" + config.getAnnotationPackage().replaceAll("\\.", "/") + "/api/common";
            manifest = new GeneratorManifest();
            manifest.setFilename("Page.java");
            manifest.setPath(_srcPath);
            manifest.setTmplName("tmpl/" + tempPath + "/Page.tmpl");
            manifests.add(manifest);
            
            manifest = new GeneratorManifest();
            manifest.setFilename("ResultBean.java");
            manifest.setPath(_srcPath);
            manifest.setTmplName("tmpl/" + tempPath + "/ResultBean.tmpl");
            manifests.add(manifest);
            
            manifest = new GeneratorManifest();
            manifest.setFilename("SearchFilter.java");
            manifest.setPath(_srcPath);
            manifest.setTmplName("tmpl/" + tempPath + "/SearchFilter.tmpl");
            manifests.add(manifest);
            
            manifest = new GeneratorManifest();
            manifest.setFilename("SearchRule.java");
            manifest.setPath(_srcPath);
            manifest.setTmplName("tmpl/" + tempPath + "/SearchRule.tmpl");
            manifests.add(manifest);
            
        }
        if (ModuleConfig.DS.equals(mconfig)) {
            manifest = new GeneratorManifest();
            manifest.setFilename("mybatis-" + module.getBizName() + "-configuration.xml");
            manifest.setPath(outPutPath + resourcesPath + "/mybatis");
            manifest.setTmplName("tmpl/" + tempPath + "/mybatis-core-configuration.tmpl");
            manifests.add(manifest);

            manifest = new GeneratorManifest();
            manifest.setFilename("spring-datasource-" + module.getBizName() + ".xml");
            manifest.setPath(outPutPath + resourcesPath + "/spring");
            manifest.setTmplName("tmpl/" + tempPath + "/spring-datasource-core.tmpl");
            manifests.add(manifest);
        }
        if (ModuleConfig.SERVER.equals(mconfig)) {
            manifest = new GeneratorManifest();
            manifest.setFilename("applicationContext.xml");
            manifest.setPath(outPutPath + resourcesPath + "/spring");
            manifest.setTmplName("tmpl/" + tempPath + "/applicationContext.tmpl");
            manifests.add(manifest);
            
            
            for (int i = 0; i < environments.length; i++) {
                String env = environments[i];
                manifest = new GeneratorManifest();
                manifest.setFilename("db.properties");
                manifest.setPath(outPutPath + resourcesPath + "/" + env + "/");
                manifest.setTmplName("tmpl/" + tempPath + "/db.tmpl");
                manifests.add(manifest);
                
                manifest = new GeneratorManifest();
                manifest.setFilename("resource.properties");
                manifest.setPath(outPutPath + resourcesPath + "/" + env + "/");
                manifest.setTmplName("tmpl/" + tempPath + "/resource.tmpl");
                manifests.add(manifest);
            }
            

            manifest = new GeneratorManifest();
            manifest.setFilename("web.xml");
            manifest.setPath(outPutPath + "/src/main/webapp/WEB-INF");
            manifest.setTmplName("tmpl/" + tempPath + "/web.tmpl");
            manifests.add(manifest);

            manifest = new GeneratorManifest();
            manifest.setFilename("log4j.xml");
            manifest.setPath(outPutPath + resourcesPath);
            manifest.setTmplName("tmpl/" + tempPath + "/log4j.tmpl");
            manifests.add(manifest);

            manifest = new GeneratorManifest();
            manifest.setFilename("spring-mvc.xml");
            manifest.setPath(outPutPath + resourcesPath + "/spring");
            manifest.setTmplName("tmpl/" + tempPath + "/spring-mvc.tmpl");
            manifests.add(manifest);
            
            manifest = new GeneratorManifest();
            manifest.setFilename("spring-redis.xml");
            manifest.setPath(outPutPath + resourcesPath + "/spring");
            manifest.setTmplName("tmpl/" + tempPath + "/spring-redis.tmpl");
            manifests.add(manifest);
            
            
            
        }
        //
        if (ModuleConfig.POJO.equals(mconfig)) {

            String _srcPath = outPutPath + SRC_MAIN_JAVA + "/" + config.getAnnotationPackage().replaceAll("\\.", "/") + "/pojo";
            manifest = new GeneratorManifest();
            manifest.setFilename("Constants.java");
            manifest.setPath(_srcPath);
            manifest.setTmplName("tmpl/" + tempPath + "/Constants.tmpl");
            manifests.add(manifest);

            manifest = new GeneratorManifest();
            manifest.setFilename("DateUtil.java");
            manifest.setPath(_srcPath);
            manifest.setTmplName("tmpl/" + tempPath + "/DateUtil.tmpl");
            manifests.add(manifest);
            
            manifest = new GeneratorManifest();
            manifest.setFilename("BeanUtil.java");
            manifest.setPath(_srcPath);
            manifest.setTmplName("tmpl/" + tempPath + "/BeanUtil.tmpl");
            manifests.add(manifest);

            manifest = new GeneratorManifest();
            manifest.setFilename("ExceptionConstants.java");
            manifest.setPath(_srcPath);
            manifest.setTmplName("tmpl/" + tempPath + "/ExceptionConstants.tmpl");
            manifests.add(manifest);
            
            manifest = new GeneratorManifest();
            manifest.setFilename("StringUtil.java");
            manifest.setPath(_srcPath);
            manifest.setTmplName("tmpl/" + tempPath + "/StringUtil.tmpl");
            manifests.add(manifest);
            
            manifest = new GeneratorManifest();
            manifest.setFilename("JsonUtils.java");
            manifest.setPath(_srcPath);
            manifest.setTmplName("tmpl/" + tempPath + "/JsonUtils.tmpl");
            manifests.add(manifest);
            
            manifest = new GeneratorManifest();
            manifest.setFilename("DynamicServerConfig.java");
            manifest.setPath(_srcPath);
            manifest.setTmplName("tmpl/" + tempPath + "/DynamicServerConfig.tmpl");
            manifests.add(manifest);

        }

        new File(outPutPath + SRC_MAIN_JAVA).mkdirs();
        new File(outPutPath + resourcesPath).mkdirs();
        new File(outPutPath + "/src/test/resources").mkdirs();
        new File(outPutPath + "/src/test/java").mkdirs();
    }


    private void createJavaModel(String className) {
        GeneratorManifest manifest;
        manifest = new GeneratorManifest();
        manifest.setFilename(className + ".java");
        manifest.setPath(outPutPath + SRC_MAIN_JAVA + "/" + config.getAnnotationPackage().replaceAll("\\.", "/"));
        manifest.setTmplName("tmpl/" + tempPath + "/" + className + ".tmpl");
        manifests.add(manifest);
    }

    public String getOutPutPath() {
        return outPutPath;
    }

    public void setOutPutPath(String outPutPath) {
        this.outPutPath = outPutPath;
    }

    public ConfigModel getConfig() {
        return config;
    }

    public void setConfig(ConfigModel config) {
        this.config = config;
    }

    public void generator() throws IOException {
        Map<String, Object> c = Maps.newHashMap();
        c.put("config", config);
        c.put("module", this.module);
        FileGenerator fg = new FileGenerator(manifests);
        fg.generator(c);
    }

}
